package uk.org.cardboardbox.neodroidpocket;

import java.nio.IntBuffer;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;



public class EmuView extends SurfaceView implements SurfaceHolder.Callback {

	private EmuThread mThread;
	private NeoGeoPocket mNGP;
	public Short fps = 0;
	
	public class EmuThread extends Thread {
		private final static String TAG = "render thread"; 
		
		
		private AudioTrack mAudioTrack;
		
		private Boolean isPaused = false;
		private Matrix scale = new Matrix();
		private Matrix noscale = new Matrix();
		private Bitmap framebuffer;
		private boolean mIsRunning = false;
		private SurfaceHolder mSurfaceHolder;
		private Integer minbuffer;
		private IntBuffer framebufferarray;
		
		public EmuThread(){
			minbuffer = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
			Log.d("xxx", minbuffer.toString());
			mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
									 	 8000, 
									 	 AudioFormat.CHANNEL_CONFIGURATION_MONO, 
									 	 AudioFormat.ENCODING_PCM_16BIT, 
									 	 minbuffer,
									 	 AudioTrack.MODE_STREAM);
			
			scale.postScale(1f, 1f);
			framebuffer = Bitmap.createBitmap(mNGP.screenx, mNGP.screeny, Bitmap.Config.ARGB_8888);
			mNGP.soundbuffer = new short[minbuffer];
			
			
			framebufferarray = IntBuffer.wrap(mNGP.framebuffer);
		}
		
		public void setSurfaceHolder(SurfaceHolder sh){
			mSurfaceHolder = sh;
		}
		
		public void pause(){
			isPaused = true;
		}
		
		public void unpause(){
			isPaused = false;
		}
		
		public void run(){
			
			
			
			Canvas c;
			
			
			//mAudioTrack.play();
			
			short catchup = 0;
			long wait = 0;
			long expectedTime = SystemClock.currentThreadTimeMillis();
			final long timePerFrame = 14;
			short framecounter = 0;
			
			while(mSurfaceHolder == null){
				try {Thread.sleep(10);} catch (Exception e){};
			}
			
			
			long timenow = SystemClock.elapsedRealtime();
			long timeonesecondlater = timenow + 1000;
			fps = 0;
			while(mIsRunning){
				timenow = SystemClock.elapsedRealtime();
				if(timenow > timeonesecondlater){
					timeonesecondlater = timenow + 1000;
					fps = framecounter;
					framecounter = 0;
				}
				
				//if(isPaused){
				//	try {
				//		this.sleep(70);
				//	} catch (InterruptedException e) {
						// TODO Auto-generated catch block
				//		e.printStackTrace();
				//	}
				//}
				//else{
					
					//expectedTime += timePerFrame; 
					
					//if(catchup > 0){
					//	mWS.execute_frame(true);
					//}
					//else {
						mNGP.jni_emulate();
						framebuffer.copyPixelsFromBuffer(framebufferarray);
						framebufferarray.rewind();
						//framebuffer = Bitmap.createBitmap(mNGP.framebuffer, mNGP.screenx, mNGP.screeny, Bitmap.Config.ARGB_8888);
						c = null;
		                try {
		                    c = mSurfaceHolder.lockCanvas();
		                    synchronized (mSurfaceHolder) {
		                    	if(mScaleDisplay)
		                    		c.drawBitmap(framebuffer, scale, null);
		                    	else
		                    		c.drawBitmap(framebuffer, noscale, null);
		                    }
		                } finally {
		                    if (c != null) {
		                        mSurfaceHolder.unlockCanvasAndPost(c);
		                    }
		                }
		                //try {
						//	this.sleep(wait);
						//} catch (InterruptedException e) {
						//	// TODO Auto-generated catch block
						//	e.printStackTrace();
						//}
						// move back out
						
					//}
					//mWS.execute_vblank();
	                
	                /*if(expectedTime > SystemClock.currentThreadTimeMillis()){
	                	catchup--;
	                	if(catchup < 0){
	                		catchup = 0;
	                	}
	                	wait += 1;
	                }
	                else if(expectedTime < SystemClock.currentThreadTimeMillis()){
	                	catchup++;
	                	if(catchup > 10){ // skipped too many frames;
	                		catchup = 0;
	                	}
	                	wait = (wait / 3);
	                }*/
		                
		               // for(Integer i = 0; i < mNGP.soundbuffer.length; i++){
		              //  	mNGP.soundbuffer[i] = i.byteValue();
		              //  }
		                
		             //mAudioTrack.write(mNGP.soundbuffer, 0, mNGP.soundbuffer.length);
		               framecounter++;
				//}
			}			
			synchronized(this){
				this.notifyAll();
			}
		}
		
		public boolean isRunning(){
			return mIsRunning;
		}
		public void setRunning(){
			mIsRunning = true;
		}
		
		public void clearRunning(){
			mIsRunning = false;
		}
		
		public void setSurfaceSize(int width, int height){
			synchronized(mSurfaceHolder){
				mSurfaceHolder.setFixedSize(width, height);
				//mVisibleWidth = width;
				//mVisibleHeight = height;
			}
		}
	}
	
	public EmuView(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		SurfaceHolder holder = this.getHolder();
		holder.addCallback(this);
		
		mThread = new EmuThread();
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		
			mThread.setSurfaceSize(width, height);
		
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		mThread.setSurfaceHolder(holder);
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		mThread.clearRunning();
	}
	
	public void setNGP(NeoGeoPocket ngp){
		mNGP = ngp;
	}
	
	public void start(){
		Log.d("view", "emulation started");
		mThread.setRunning();
		mThread.start();
		
	}
	
	private boolean mPaused = false;
	public void togglepause(){
		if(mPaused){
			mPaused = false;
			mThread.unpause();
		}
		else {
			mPaused = true;
			mThread.pause();
		}
	}
	
	
	public void onResume(){
			mThread = new EmuThread();
			start();
	}
	
	public boolean stop(){
		if(mThread.isRunning()){
			Log.d("view", "shutting down emulation");
			
			
			mThread.clearRunning();
			
			synchronized (mThread){
			try {
				mThread.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}}
			
			//try {
			//	Thread.sleep(100);
			//} catch (InterruptedException e) {
			//	// TODO Auto-generated catch block
			//	e.printStackTrace();
			//}
			
			return true;
		}
		return false;
	}

	private boolean mScaleDisplay = true;
	void enableScale(){
		mScaleDisplay = true;
	}
	
	void disableScale(){
		mScaleDisplay = false;
	}
}
